import java.util.*;
import java.io.*;

/**
 * Board class Datastructure + methods representing board and it's fields
 * 
 * @author kkopiec
 * 
 */
public class Board {
	protected static int boardSize = 15;
	public static Field[][] pBoard = new Field[boardSize][boardSize];
	protected static Field[][] previousBoard;
	protected static Setup lastSetup;
	protected static ArrayList<String> crosswords;
	protected static enum Position{
		CENTER,
		LEFT,
		RIGHT
	}

	public Board() {
		wipeBoard();
		File propsFile = new File("nerdlefield.props");
		try {
			Scanner sc = new Scanner(propsFile);
			//sc.useDelimiter(" ");
			while ( sc.hasNextLine()){
				Scanner prsr = new Scanner(sc.nextLine());
				prsr.useDelimiter(" ");
				int y = prsr.nextInt();
				int x = prsr.nextInt();
				FieldProps props = FieldProps.NONE;
				String type = prsr.next();
				int value = prsr.nextInt();
				
				if (type.equals("l")) props = FieldProps.LETTER;
				if (type.equals("w")) props = FieldProps.WORD;
				
				pBoard[y][x].setPropType(props);
				pBoard[y][x].setPropValue(value);
			}
		} catch (FileNotFoundException ex) {
			System.out.println("Board property file not found");
		}
		
	}
	
	public static void wipeBoard(){
		for (int x = 0; x < boardSize; x++) {
			for (int y = 0; y < boardSize; y++) {
				pBoard[x][y] = new Field(FieldProps.NONE, 1);

			}

		}
		
	}

	public static void putSetup(Setup s) {
		lastSetup = s;
		crosswords = s.crosswords;
		String crossFront = ""; // front part of crossword
		String crossTail = ""; // rear part of crossword
		String crossWhole = ""; // whole crossword
		int partialScore = 0; // partial score just for what we've put
		int numOfCrossings;
		// previousBoard = (Field[][])pBoard.clone();
		previousBoard = new Field[boardSize][boardSize];
		for (int ix = 0; ix < boardSize; ix++) {
			for (int yk = 0; yk < boardSize; yk++) {
				previousBoard[ix][yk] = new Field(pBoard[ix][yk]);
			}
		}
		
		int x = Math.abs('A' - s.getX());
		int y = s.getY() - 1;
		int w = 1;				// word multiplier
		int l = 0;				// sum of letters
		numOfCrossings = 0;		// number of crossings
		switch (s.getDir()) {
		case RIGHT:
			if ((int) (14 - x) < s.getWordStr().length()) {
				// Not enough room for tiles
				s.success(false);

			} else {
				boolean canPut = false || pBoard[7][7].tiled
						|| ((x + s.getWordStr().length() >= 7) && (y == 7)); // is
																				// central
																				// point
																				// tiled
																				// ?
				if (canPut) {
					for (int p = x; p < x + s.getWordStr().length(); p++) {		// for each letter of our word
						if (pBoard[y][p].tiled) {                               // if we find a tiled field on the board
							numOfCrossings ++;									// we increment number of crossings	
							if (s.getWordStr().charAt(p - x) == pBoard[y][p]	// if our word contains the letter found on the board
									.getLetter()) {
								canPut = true;									// we believe we can put the word
							} else
								canPut = false;                                 // otherwise we cannot
						} else {
							if ((y > 0 && pBoard[y-1][p].tiled) || (y < 14 && pBoard[y+1][p].tiled)) numOfCrossings++; 	// if we didn't meet any other
																													   	// tiles on the way but there are some
																														// on the neighbour fields
						}																								// we increment number of crossings
					}
					canPut = canPut && (numOfCrossings > 0 || !pBoard[7][7].tiled) ;									// final decision: if we got all needed letters 
				}																										// and we can cross or at least attach the word to the existing one unless it is very first word on the board
				////////////////////////////////////////////////////////////////////////////////////////////////
				// we are putting tiles on board from now on 
				if (!canPut)
					s.success(false);
				else { 
					l = 0;  // reset sum of letters
					w = 1;  // reset word-multiplier
					for (Tile e : s.word) {								// for each of tiles we want to put
						crossWhole = "";         // crossing word
						crossFront = "";         // 1st part of the crossing
						crossTail = "";         //  2nd part of the crossing

						while (pBoard[y][x].tiled) {                		// if there is a tile already existing in the place
							l += pBoard[y][x].getTileValue();			// just add its value to the total score
							x++;										// move to the next position

						} 
						pBoard[y][x].setTile(e);								// put tile on the board
						if (pBoard[y][x].getPropType() == FieldProps.WORD) { 	// if field got property word multiplier
							w = w * pBoard[y][x].getPropValue();      			// multiply word-multiplier value 
							l += pBoard[y][x].getTileValue();					// add tile value to the sum of tiles
						}
						if (pBoard[y][x].getPropType() == FieldProps.LETTER)    // if field property is letter multiplier
							l += pBoard[y][x].getTileValue()         			// multiply tile value by letter multiplier
									* pBoard[y][x].getPropValue();				// and add it to the sum of letters
						if (pBoard[y][x].getPropType() == FieldProps.NONE)		// if field property is NONE
							l += pBoard[y][x].getTileValue();					// just add tile value to the sum of letters
						pBoard[y][x].clearProps();								// finally clear the properties of the field
						partialScore += l;										// the score = word-multiplier * sum of letters
						l = 0;
						//////////////////////////////////////////////////////////////
						// Check crossings
						

						crossWhole += pBoard[y][x].getLetter(); 						// Get the tile we've just put     
						int cwords = 0;																// 
						int tmpy = y + 1;												// set pointer to the next row
						while (tmpy < boardSize && pBoard[tmpy][x].tiled) { 			// while it is not beyond last row check if there is another tile 
							l += pBoard[tmpy][x].getTileValue();						// if so add it's value to the sum of letters
							crossTail += pBoard[tmpy][x].getLetter();					// add the letter to the tail of crossword 
							cwords++;													// indicate that there was some crossword found
																						// so that we can add the value of tile just put twice
							tmpy++;														// go to the next row
						}
						tmpy = y - 1;													// set pointer to the previous row
						while (tmpy > -1 && pBoard[tmpy][x].tiled) {					// while the it is still on the board check if it is tiled
							l += pBoard[tmpy][x].getTileValue();						// if so add tile value to the sum of letters
							crossFront += pBoard[tmpy][x].getLetter();					// add letter to the front of the crossword
							cwords++;													// indicate that there was some crosswords
																						// so that we can calculate value of tile
																						// we've just put into another word created
							tmpy--;														// move to the previous row
						}
						if (cwords > 0) l+= pBoard[y][x].getTileValue();				// if there was a crossing we need to add the tile we've just put again to the score
																						// as a part of another word
						// ///////////////////////////////////////////////////////////
						x++;															// move to the next field to be tiled
						crossWhole = new StringBuffer(crossFront).reverse()				// assembly crossword
								+ crossWhole + crossTail;								//
						crosswords.add(crossWhole);										// and add it to the list of crosswords	

					}

						s.setScore(w * partialScore + l);									// calculate and return score for setup
																						// what we've calculated for the tiles we've put + all crosswords 
						s.success(true);												// inform setup that it was successful  
					
				}
			}
			break;
			
		case DOWN:
			if (14 - y < s.getWordStr().length()) {
				s.success(false);
			} else {
				boolean canPut = false || pBoard[7][7].tiled
						|| ((y + s.getWordStr().length() >= 7) && (x == 7)); //check if middle field is tiled
				if (canPut) {
					for (int p = y; p < y + s.getWordStr().length(); p++) {    // for each letter of the word we want to put
						if (pBoard[p][x].tiled) {                              // if there is a tile on the way
							numOfCrossings++;
							if (s.getWordStr().charAt(p - y) == pBoard[p][x]   // word we want to put
									.getLetter()) {							   //  must contain this letter
								canPut = true;                                 // if so we can assume that we can put word 
							} else
								canPut = false;                               // otherwise we cannot
						} else {
							if ((x > 0 && pBoard[p][x-1].tiled) || (x < 14 && pBoard[p][x+1].tiled)) numOfCrossings++; 	// if we didn't meet any other
						   																								// tiles on the way but there are some
																														// on the neighbour fields
							}																							// we increment number of crossings
					}
					canPut = canPut && (numOfCrossings > 0 || !pBoard[7][7].tiled) ;									// final decision: if we got all needed letters 
				}																										// and we can cross or at least attach the word to the existing one unless it is very first word on the board
				//////////////////////////////////////////////////////////////////////////////////
				// putting tiles on board from now on
				if (!canPut)
					s.success(false);
				else {
					w = 1;
					l = 0;
					for (Tile e : s.word) {
						crossWhole = "";
						crossFront = "";
						crossTail = "";
						while (pBoard[y][x].tiled) {
							l += pBoard[y][x].getTileValue();
							y++;
						}
						pBoard[y][x].setTile(e);
						if (pBoard[y][x].getPropType() == FieldProps.WORD) {
							w = w * pBoard[y][x].getPropValue();
							l += pBoard[y][x].getTileValue();
						}
						if (pBoard[y][x].getPropType() == FieldProps.LETTER)
							l += pBoard[y][x].getTileValue()
									* pBoard[y][x].getPropValue();
						if (pBoard[y][x].getPropType() == FieldProps.NONE)
							l += pBoard[y][x].getTileValue();
						pBoard[y][x].clearProps();
						partialScore += l;
						l = 0;
						////////////////////////////////////////////////////////////////
						// Check for crosswords
						crossWhole += pBoard[y][x].getLetter(); // make up
																// crossing
						int cwords = 0;
						int tmpx = x + 1;
						while (tmpx < boardSize && pBoard[y][tmpx].tiled) {
							cwords++;
							l += pBoard[y][tmpx].getTileValue();
							crossTail += pBoard[y][tmpx].getLetter(); // make up
																		// crossing
							tmpx++;
						}
						tmpx = x - 1;
						while (tmpx > -1 && pBoard[y][tmpx].tiled) {
							cwords++;
							l += pBoard[y][tmpx].getTileValue();
							crossFront += pBoard[y][tmpx].getLetter();// make up
																		// crossing
							tmpx--;
						}
						if (cwords > 0) l+= pBoard[y][x].getTileValue();				// if there was a crossing we need to add the tile we've just put again to the score
						// ///////////////////////////////////////////////////////////
						crossWhole = new StringBuffer(crossFront).reverse()
								+ crossWhole + crossTail;// make up crossing
						crosswords.add(crossWhole);// make up crossing
						y++;

					}
					

						s.setScore(w * partialScore + l);
						s.success(true);
					
				}

			}
			break;
		}
		// Display.refresh();

	}

	public static int getBoardSize() {
		return boardSize;
	}

	public static void fixBoard(boolean fix) {
		if (!fix) {
			pBoard = previousBoard;
			lastSetup.challenged();

		}

	}

	public static Setup lastSetup() {
		return lastSetup;
	}
	
	public static void displayOnBoard(String text, Position pos, int lineNo ){
		int col;
		int row = lineNo;
		if (text.length() > boardSize -1) text.substring(0, boardSize -1);
		switch (pos){
		case LEFT:
			col = 1;
			break;
		case CENTER:
			col = boardSize/2 - text.length()/2;
			break;
		case RIGHT:
			col = boardSize -1 - text.length();
			break;
		default:
			col = 1;
		}
		for (int i = 0; i < text.length();i++){
			pBoard[row][col+i].setTile(new Tile(text.charAt(i), 0));
		}
		
	}

}
